<!DOCTYPE html>
<!--
Copyright (c) 2015 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->

<link rel="import" href="/tracing/base/utils.html">
<link rel="import" href="/tracing/model/event_set.html">

<script>
'use strict';

tr.exportTo('tr.model', function() {
  function getAssociatedEvents(irs) {
    const allAssociatedEvents = new tr.model.EventSet();
    irs.forEach(function(ir) {
      ir.associatedEvents.forEach(function(event) {
        // FlowEvents don't have parentContainers or cpuDurations, and it's
        // annoying to highlight them.
        if (event instanceof tr.model.FlowEvent) return;
        allAssociatedEvents.push(event);
      });
    });
    return allAssociatedEvents;
  }

  function getUnassociatedEvents(model, associatedEvents) {
    const unassociatedEvents = new tr.model.EventSet();
    // The set of unassociated events contains only events that are not in
    // the set of associated events.
    // Only add event to the set of unassociated events if it is not in
    // the set of associated events.
    for (const proc of model.getAllProcesses()) {
      for (const thread of Object.values(proc.threads)) {
        for (const event of thread.sliceGroup.getDescendantEvents()) {
          if (!associatedEvents.contains(event)) {
            unassociatedEvents.push(event);
          }
        }
      }
    }
    return unassociatedEvents;
  }

  function getTotalCpuDuration(events) {
    let cpuMs = 0;
    events.forEach(function(event) {
      // Add up events' cpu self time if they have any.
      if (event.cpuSelfTime) {
        cpuMs += event.cpuSelfTime;
      }
    });
    return cpuMs;
  }

  function getIRCoverageFromModel(model) {
    const associatedEvents = getAssociatedEvents(model.userModel.expectations);

    if (!associatedEvents.length) return undefined;

    const unassociatedEvents = getUnassociatedEvents(
        model, associatedEvents);

    const associatedCpuMs = getTotalCpuDuration(associatedEvents);
    const unassociatedCpuMs = getTotalCpuDuration(unassociatedEvents);

    const totalEventCount = associatedEvents.length + unassociatedEvents.length;
    const totalCpuMs = associatedCpuMs + unassociatedCpuMs;
    let coveredEventsCpuTimeRatio = undefined;
    if (totalCpuMs !== 0) {
      coveredEventsCpuTimeRatio = associatedCpuMs / totalCpuMs;
    }

    return {
      associatedEventsCount: associatedEvents.length,
      unassociatedEventsCount: unassociatedEvents.length,
      associatedEventsCpuTimeMs: associatedCpuMs,
      unassociatedEventsCpuTimeMs: unassociatedCpuMs,
      coveredEventsCountRatio: associatedEvents.length / totalEventCount,
      coveredEventsCpuTimeRatio
    };
  }

  return {
    getIRCoverageFromModel,
    getAssociatedEvents,
    getUnassociatedEvents,
  };
});
</script>
